#include "Entity/IEntity.hpp"
#include "Common.hpp"
#include "Graphics/ISprite.hpp"
#include "Math/Vector.hpp"
#include "Physics/IBody.hpp"

#include <iostream>
#include <queue>
#include <string>
#include <vector>

namespace Entity
{
	std::vector< IEntity * > IEntity::entityList;

	IEntity::IEntity( void )
		: angle( 0.0f ), angVel( 0.0f )
	{
		if ( availableIDs.empty() )
		{
			id = entityList.size();
			entityList.push_back( this );
		}
		else
		{
			id = availableIDs.front();
			availableIDs.pop();
			entityList[ id ] = this;
		}
	}

	IEntity::~IEntity( void )
	{
		entityList[ id ] = nullptr;
		availableIDs.push( id );

		if ( GetSprite() )
		{
			delete GetSprite();
		}
		if ( GetPhysicsBody() )
		{
			delete GetPhysicsBody();
		}
	}

	void IEntity::Think( const float frameTime )
	{
	}

	void IEntity::Draw( void )
	{
	}

	void IEntity::Remove( void )
	{
	}

	std::string IEntity::GetClass( void ) const
	{
		return className;
	}

	void IEntity::SetClass( const std::string setClass )
	{
		className = setClass;
	}

	Graphics::ISprite *IEntity::GetSprite( void )
	{
		return nullptr;
	}

	Physics::IBody *IEntity::GetPhysicsBody( void )
	{
		return nullptr;
	}

	float IEntity::GetAngle( void ) const
	{
		return angle;
	}

	void IEntity::SetAngle( const float ang )
	{
		angle = ang;
	}

	Math::Vectorf IEntity::GetPosition( void ) const
	{
		return position;
	}

	void IEntity::SetPosition( const Math::Vectorf &pos )
	{
		position = pos;
	}

	Math::Vectorf IEntity::GetSize( void ) const
	{
		return size;
	}

	void IEntity::SetSize( const Math::Vectorf &vec )
	{
		size = vec;

		if ( GetSprite() )
		{
			GetSprite()->SetSize( vec );
		}
	}

	float IEntity::GetAngularVelocity( void ) const
	{
		return angVel;
	}

	void IEntity::SetAngularVelocity( const float vel )
	{
		angVel = vel;
	}

	Math::Vectorf IEntity::GetLinearVelocity( void ) const
	{
		return linVel;
	}

	void IEntity::SetLinearVelocity( const Math::Vectorf &vel )
	{
		linVel = vel;
	}

	unsigned IEntity::Number( void )
	{
		return entityList.size();
	}

	IEntity *IEntity::GetByID( const unsigned getID )
	{
		return entityList[ getID ];
	}

	void IEntity::ThinkAll( const float frameTime )
	{
		std::vector< IEntity * >::iterator itr = entityList.begin();

		for ( ; itr != entityList.end(); ++itr )
		{
			if ( *itr != nullptr )
			{
				( *itr )->Think( frameTime );
			}
		}
	}
}